package org.jeecg.modules.miniAppCustomerEndPoint.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.google.common.base.Joiner;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.system.base.controller.JeecgController;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.modules.hc.entity.HcSiteAddressDetails;
import org.jeecg.modules.hc.service.IHcSiteAddressDetailsService;
import org.jeecg.modules.miniAppCustomerEndPoint.entity.JxUserDo;
import org.jeecg.modules.miniAppCustomerEndPoint.mapper.JxUserMapper;
import org.jeecg.modules.miniAppCustomerEndPoint.utils.GeoUtil;
import org.jeecg.modules.miniAppCustomerEndPoint.utils.JxUserUtil;
import org.jeecg.modules.platformMasterEndPoint.entity.JxSiteDetailDo;
import org.jeecg.modules.platformMasterEndPoint.mapper.JxSiteDetailMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;

/**
 * @Description: 站点地址明细
 * @Author: jeecg-boot
 * @Date: 2022-12-13
 * @Version: V1.0
 */
@Api(tags = "站点地址明细")
@RestController
@RequestMapping("/jx/jxSiteAddressDetails")
@Slf4j
public class JxSiteDetailController extends JeecgController<HcSiteAddressDetails, IHcSiteAddressDetailsService> {
    @Autowired
    private IHcSiteAddressDetailsService hcSiteAddressDetailsService;

    @Autowired
    private JxSiteDetailMapper jxSiteDetailMapper;

    @Autowired
    private JxUserMapper jxUserMapper;

    @ApiOperation("根据大厦id获取下单地址列表")
    @GetMapping("/getListByAddressId")
    public Result<?> getListByAddressId(@RequestParam(name = "addressId")String addressId,@RequestParam(name = "merchantId") String merchantId) {
        return Result.ok(hcSiteAddressDetailsService.getListByAddressId(addressId,merchantId));
    }

    @ApiOperation("修改大厦取餐地址展示情况")
    @PostMapping("/editAddressShowState")
    public Result<?> editAddressShowState(@RequestBody HcSiteAddressDetails param) {
        //根据id 获取大厦信息
        HcSiteAddressDetails hcSiteAddressDetails = hcSiteAddressDetailsService.getById(param.getId());
        if (null == hcSiteAddressDetails ){
            throw new JeecgBootException("未找到大厦信息");
        }
        String jsonSupplyAddress = hcSiteAddressDetails.getSupplyAddress();
        if (StringUtils.isNotBlank(jsonSupplyAddress)){
            JSONArray jsonArray = JSON.parseArray(jsonSupplyAddress);
            for (int i = 0; i < jsonArray.size(); i++) {
                JSONObject jsonObject = jsonArray.getJSONObject(i);
                String code = jsonObject.getString("code");
                //将id塞到json里面
                String supplyMerchantIds = jsonObject.getString("supplyMerchantIds");
                if (code.equals(param.getSupplyAddressCode())){
                    if (param.getIsShowAddress().equals("true")){//开启。需要将id去除
                        List<String> merchantIds = new ArrayList<>(Arrays.asList(supplyMerchantIds.split(",")));
                        List<String> merchantIdsToRemove = new ArrayList<>();

                        if (!merchantIdsToRemove.isEmpty()) {
                            merchantIds.removeAll(merchantIdsToRemove);
                            if (CollectionUtils.isNotEmpty(merchantIds)) {
                                String merchantIdString = Joiner.on(",").join(merchantIds);
                                jsonObject.put("supplyMerchantIds", merchantIdString);
                            } else {
                                jsonObject.put("supplyMerchantIds", "");
                            }
                        }
                    }else {//关闭，将id加进去
                    }
                }
            }
            hcSiteAddressDetails.setSupplyAddress(jsonArray.toJSONString());
            hcSiteAddressDetailsService.updateById(hcSiteAddressDetails);
        }
        return Result.ok("修改成功");
    }


    @ApiOperation("获取用户之前保存的大厦地址")
    @GetMapping("/queryUserAddress")
    public Result<?> getUserAddress(
            HttpServletRequest request) {
        String token = request.getHeader("X-Access-Token");
        String userId = JxUserUtil.getUserId(token, null);
        // 但是此处没有使用 getOne() 而是使用 list()，原因是，理论上hc_user 表中open_id 是唯一的，但是可能由于bug或历史数据残留，导致通过某个open_id查询，会返回多条记录
        // 此种场景下 getOne() 会抛出异常，getOne() 会对查询出来的结果集进行判断，查询的结果集中只能是1条，0或多条都会抛出异常
        List<JxUserDo> list = jxUserMapper.selectList(new LambdaQueryWrapper<JxUserDo>().eq(JxUserDo::getId, userId).orderByAsc(JxUserDo::getUpdateTime));
        HashMap<String, Object> resultData = new HashMap<>();
        if (list != null && list.size() > 0) {
            JxUserDo userDetail = list.get(0);
            resultData.put("siteId", userDetail.getSiteId());
            resultData.put("addressId", userDetail.getSiteId());
            JxSiteDetailDo siteDetailDo = jxSiteDetailMapper.selectById(userDetail.getSiteId());
            // 返回的是站点的名称，用来展示在【首页】 左上角 下拉列表框中
            resultData.put("addressName", siteDetailDo.getSiteName());
        } else {
            resultData.put("siteId", null);
            resultData.put("addressId", null);
            resultData.put("addressName", null);
            log.error("获取用户之前保存的大厦地址失败，可能的原因是：从 hc_user 表中找不到 id 为 {} 的数据行", userId);
        }
        return Result.ok(resultData);
    }

    /**
     * 返回下单页面中，用户可以选着的大厦列表；该请求无传参，
     * @return
     */
    @ApiOperation("获取所有站点大厦地址")
    @GetMapping("/queryAllSiteAddress")
    public Result<?> getAddressList() {
        List<JxSiteDetailDo> siteList = jxSiteDetailMapper.selectList(new QueryWrapper<JxSiteDetailDo>());
        List<HashMap<String, String>> allSiteAddrBriefDescriptions = new ArrayList<>();
        // 循环遍历所有的站点大厦 经纬度坐标
        for (int i = 0 ; i < siteList.size(); i ++) {
            JxSiteDetailDo oneSiteDetail = siteList.get(i);

            HashMap<String, String> siteAddrBriefDescription = new HashMap<>();
            siteAddrBriefDescription.put("siteId", oneSiteDetail.getId());
            siteAddrBriefDescription.put("addressId", oneSiteDetail.getId());
            siteAddrBriefDescription.put("addressName", oneSiteDetail.getSiteName());
            allSiteAddrBriefDescriptions.add(siteAddrBriefDescription);
        }
        HashMap<String, Object> resultData = new HashMap<>();
        resultData.put("allAddress", allSiteAddrBriefDescriptions);
        String errMsg = "";
        if (allSiteAddrBriefDescriptions.size() == 0 ) {
            errMsg = "找不到可供用户选择的大厦，可能的原因是，从 site addr details 表中查询已知站点大厦信息，查询结果为空";
        }

        return Result.OK(errMsg, resultData);
    }

    /**
     * 根据用户手机定位获取到的GPS 经纬度，与当前各个站点大厦之间计算距离，返回最近的一个大厦的 ID 和名称；同时也会返回所有站点大厦的 ID 和名称；
     * 因为 手机GPS 定位 存在如下问题，因此，改接口返回的只能是 “根据用户坐标，推荐的最佳匹配的大厦”，因此，除了返回推荐的距离最近的大厦，也返回了其他所有大厦的地址，让用户自行判断和挑选
     * 1. 用户打开小程序，手机定位的地点，有小概率可能不是用户所在的大厦，可能是在用户 上下班路上 打开小程序；
     * 2. 手机定位精度 很难保障，存在小概率定位失败的问题；
     * 3. 当前使用的根据两个点经纬度，计算距离的开源工具类，经过实际测试，误差在10米 这个级别；如果用户所在办公地点，有两个大厦，很可能由于计算精度问题，导致后端判断错了用户所在大厦
     * @param latitude 用户手机定位后，得到的用户所在的位置的 精度值
     * @param longitude 用户手机定位后，得到的用户所在的位置的 纬度值
     * @return 离用户最近的大厦 和 所有大厦信息列表（计算结果不准时，供用户手动选择）
     */
    @ApiOperation("获取地址列表")
    @GetMapping("/queryNearnestSiteAddrByLongLat")
    public Result<HashMap<String, Object>> queryNearestSiteAddressByLatLong(
            @RequestParam("latitude") double latitude,
            @RequestParam("longitude") double longitude) {

        double minDistance = Double.MAX_VALUE;
        JxSiteDetailDo nearnestSiteAddr = null;
        List<JxSiteDetailDo> siteList =  jxSiteDetailMapper.selectList(new LambdaQueryWrapper<JxSiteDetailDo>());

        List<HashMap<String, String>> allSiteAddrBriefDescriptions = new ArrayList<>();
        // 循环遍历所有的站点大厦 经纬度坐标
        for (int i = 0 ; i < siteList.size(); i ++) {
            JxSiteDetailDo oneSiteDetail = siteList.get(i);
            double siteAddrLat = oneSiteDetail.getLatitude().doubleValue();
            double siteAddrLong = oneSiteDetail.getLongitude().doubleValue();
            // 计算用户所在位置经纬度，与某一个站点大厦的坐标之间的距离
            double distance = GeoUtil.getDistance(longitude, latitude, siteAddrLong, siteAddrLat);
            // 找出离用户最近的大厦的距离
            if (distance < minDistance) {
                minDistance = distance;
                nearnestSiteAddr = oneSiteDetail;
            }

            HashMap<String, String> siteAddrBriefDescription = new HashMap<>();
            siteAddrBriefDescription.put("siteId", oneSiteDetail.getId());
            siteAddrBriefDescription.put("addressId", oneSiteDetail.getId());
            siteAddrBriefDescription.put("addressName", oneSiteDetail.getSiteName());
            allSiteAddrBriefDescriptions.add(siteAddrBriefDescription);
        }
        String errMsg = "";
        HashMap<String, Object> resultData = new HashMap<>();
        if (nearnestSiteAddr != null) {
            resultData.put("nearnestSiteId", nearnestSiteAddr.getId());
            resultData.put("nearnestAddrId", nearnestSiteAddr.getId());
            resultData.put("nearnestAddrName", nearnestSiteAddr.getSiteName());
            // 当找到了离用户最近的大厦，则 allAddress 为空数组
            resultData.put("allAddress", new ArrayList<>());
        } else {
            // 找不到距离用户最近的大厦，可能的原因是，从 hc_site_address_details 表中查询已知站点大厦信息，查询结果为空
            resultData.put("nearnestSiteId", null);
            resultData.put("nearnestAddrId", null);
            resultData.put("nearnestAddrName", null);
            resultData.put("allAddress", allSiteAddrBriefDescriptions);
            errMsg = "找不到距离用户最近的大厦，可能的原因是，从 hc_site_address_details 表中查询已知站点大厦信息，查询结果为空";
        }
        return Result.OK(errMsg, resultData);
    }

    /**
     * 1.10 根据站点id，查询站点的供餐时间段，用来供前端显示倒计时
     * @param siteId 站点id
     * @return
     */
    @ApiOperation(value = "查询站点供餐时间段，用来显示倒计时", notes = "查询站点供餐时间段，用来显示倒计时")
    @GetMapping(value = "/querySiteSupplyTimeSpan")
    public Result<?> querySiteSupplyTimeSpan(
            @RequestParam("siteId") String siteId) {

        JxSiteDetailDo siteDetailDo = jxSiteDetailMapper.selectById(siteId);
        HashMap<String,Object> resultData = new HashMap<>();
        String errMsg = "";
        if (siteDetailDo == null) {
            JSONObject defaultTimeSpan = new JSONObject();
            defaultTimeSpan.put("beginTime", "19:00:00");
            defaultTimeSpan.put("endTime", "10:30:00");
            resultData.put("supplyTimeSpan",defaultTimeSpan);
            errMsg = "无法从site addr detail表中找到大厦信息，使用默认时间段";
            log.error("无法从site addr detail表中找到id为 {} 的大厦信息", siteId);
        } else {
            JSONObject timeSpan = JSONObject.parseObject(siteDetailDo.getSupplyTimeSpan());
            resultData.put("supplyTimeSpan", timeSpan);
        }

        return Result.OK(errMsg,resultData);
    }

    /**
     * 两种场景会调用此接口
     * 1. 用户在 【首页】 通过站点下拉列表，选择不同站点
     * 2. 用户在 提交订单时，在订单页面，填写收货地址时，选择不同的站点
     * @param siteId
     * @return
     */
    @ApiOperation(value = "更新用户所在站点id和名称", notes = "更新用户所在站点id和站点名称")
    @PutMapping("/updateUserSiteInfo")
    public Result<?> updateUserSiteInfo(
            @RequestParam(value = "userId", required = false) String userId,
            @RequestParam("siteId") String siteId) {

        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        String userId2 = null;
        if (sysUser == null) {
            userId2 = userId;
        } else {
            userId2 = sysUser.getId();
        }
        JxUserDo jxUserDo = jxUserMapper.selectById(userId2);
        if (jxUserDo != null) {
            // 若用户表中存在 用户信息，则更新用户的 站点信息（id和名称）;
            JxUserDo jxUserDo2 = new JxUserDo();
            jxUserDo2.setId(userId2);
            jxUserDo2.setSiteId(siteId);
            jxUserMapper.updateById(jxUserDo2);
        } else {
            // 若用户表中无此用户，则新增一条记录，则打印日志，返回错误提示，不要影响用户其他操作
            // 正常场景下，当用户通过微信授权登录后，jx_user 表中就会为该用户添加一条记录
            log.error("在用户表中找不到 id: {} 的用户记录，用户表中用户信息数据存在缺失，需要由后台技术人员进行排查", userId2);
        }

        return Result.ok();
    }


    /**
     * 接口1.25 获取各个站点配置的轮播图图片列表
     * @param siteId
     * @return
     */
    @ApiOperation(value = "首页轮播图图片列表", notes = "首页轮播图图片列表")
    @GetMapping("/queryCarouselChartImages")
    public Result<?> queryCarouselChartImages(
            @RequestParam("siteId") String siteId){

        List<JxSiteDetailDo> list = jxSiteDetailMapper.selectList(new LambdaQueryWrapper<JxSiteDetailDo>().eq(JxSiteDetailDo::getId, siteId));
        if (list != null && list.size() > 0) {
            JxSiteDetailDo siteDetailDo = list.get(0);
            JSONArray carousels = JSONObject.parseArray(siteDetailDo.getCarousels());
            return Result.ok(carousels);
        } else {
            // 若找不到，则返回默认的轮播图图片列表
            List<String> carousels = new ArrayList<>();
            carousels.add("http://btprint.yongshantuan.cn/static/images/carousels/carousel_1.jpg");
            carousels.add("http://btprint.yongshantuan.cn/static/images/carousels/carousel_2.jpg");
            carousels.add("http://btprint.yongshantuan.cn/static/images/carousels/carousel_3.jpg");
            return Result.ok(carousels);
        }
    }
}
